from neutron import Plugin, execute, User, OS, Shutil
from fastapi import HTTPException
import os as real_os
import tarfile
import random
import tomllib

SYS_PLUGIN_PATH = real_os.path.abspath("plugins")
USER_PLUGIN_PATH = real_os.path.abspath("config/plugins")

need_restart = False


def get_plugin_path(sys_plugin):  # 获取插件路径
    if sys_plugin:
        return SYS_PLUGIN_PATH
    else:
        return USER_PLUGIN_PATH


def remove_suffix(s, suffix):  # 去后缀
    if s.endswith(suffix):
        return s[:-len(suffix)]
    return s


def main(app: Plugin):
    @app.route.get("/plugin", level=2)
    async def get_plugins(user: User, sys_plugin: bool = False):  # 获取插件列表
        global need_restart
        os = OS(user)
        if (not await app.checker.check_func_permission(user, 2, "plugin")):
            raise HTTPException(status_code=403)
        plug_path = get_plugin_path(sys_plugin)
        if (await os.path.exists(plug_path)):
            pluglist = [
                {
                    "name": remove_suffix(i, ".disable"),
                    "path": plug_path+os.sep+i,
                    "disable": i.endswith(".disable")
                } for i in await os.listdir(plug_path) if
                (i != "neuplugin"
                 and i != ".NEUTRON_PLUGIN"
                 and not i.startswith(".cache")
                 and await os.path.exists(plug_path+os.sep+i+os.sep+"manifest.toml"))]
        else:
            pluglist = []
        return {
            "code": 0,
            "msg": "",
            "data": {
                "list": pluglist,
                "needrestart": need_restart
            }
        }

    @app.route.post("/plugin/remove", level=2)
    async def remove_plugin(user: User, plug_name: str):  # 删除插件
        global need_restart
        os = OS(user)
        shutil = Shutil(user)
        if (not await app.checker.check_func_permission(user, 2, "plugin")):
            raise HTTPException(status_code=403)
        plug_path = USER_PLUGIN_PATH+os.sep+plug_name
        need_restart = True
        if (not await os.path.exists(plug_path)):
            plug_path = plug_path + ".disable"
            if (not await os.path.exists(plug_path)):
                return {
                    "code": 1,
                    "msg": "找不到插件"
                }
        await shutil.rmtree(plug_path)
        return {
            "code": 0,
            "msg": ""
        }

    @app.route.post("/plugin/install", level=2)
    async def install_plugin(user: User, plug_file_path: str):  # 安装插件
        global need_restart
        os = OS(user)
        shutil = Shutil(user)
        if (not await app.checker.check_func_permission(user, 2, "plugin")):
            raise HTTPException(status_code=403)
        if (not await os.path.exists(plug_file_path)):
            return {
                "code": 1,
                "msg": "找不到文件"
            }
        need_restart = True
        if (not await os.path.isfile(plug_file_path)):  # 不是压缩插件
            return {
                "code": 1,
                "msg": "找不到文件"
            }

        async def install_task(tasktool):
            global need_restart
            rand_id = ".cache"+str(random.randint(100000, 999999))  # 生成随机目录
            await tasktool.set_process(0)
            await tasktool.write_log("开始安装"+"\n")
            await os.makedirs(USER_PLUGIN_PATH+os.sep +
                              rand_id, exist_ok=True)
            await tasktool.set_process(10)
            await tasktool.write_log("解压插件"+"\n")

            def unzip_cmd():
                try:
                    with tarfile.open(plug_file_path, "r:xz") as tar:  # 解压
                        tar.extractall(USER_PLUGIN_PATH+os.sep +
                                       rand_id)
                    return False
                except:  # 异常处理只能在内部进行
                    return True  # 吐槽 async 异常抛不出去
            if (await os.run(unzip_cmd)):
                await tasktool.write_log("解压失败"+"\n正在清理\n")
                await shutil.rmtree(USER_PLUGIN_PATH+os.sep+rand_id)
                await tasktool.exit(True)
                return
            await tasktool.set_process(70)
            await tasktool.write_log("读取元信息"+"\n")
            try:
                async with os.open(USER_PLUGIN_PATH+os.sep+rand_id+os.sep+"manifest.toml",
                                   "r") as f:
                    manifest = tomllib.loads(await f.read())
                real_plug_name = manifest["common"]["name"]
                await tasktool.write_log(
                    "  插件 id: "+real_plug_name+"\n")
                await tasktool.write_log(
                    "  插件版本: "+manifest["common"]["version"]+"\n")
                await tasktool.write_log(
                    "  插件作者: "+manifest["common"]["author"]+"\n")
                await tasktool.write_log(
                    "  插件描述: "+manifest["common"]["description"]+"\n")
            except:  # 利用KeyError同时检查元数据
                await tasktool.write_log("读取元信息失败"+"\n正在清理\n")
                await shutil.rmtree(USER_PLUGIN_PATH+os.sep+rand_id)
                await tasktool.exit(True)
                return
            await tasktool.set_process(80)
            plug_path = USER_PLUGIN_PATH+os.sep+real_plug_name
            if (await os.path.exists(plug_path)):
                await tasktool.write_log("删除旧版本\n")
                await shutil.rmtree(plug_path)
            if (await os.path.exists(plug_path+".disable")):  # 处理禁用的情况
                await tasktool.write_log("删除旧版本\n")
                await shutil.rmtree(plug_path+".disable")
            await shutil.move(USER_PLUGIN_PATH+os.sep+rand_id, plug_path)
            await tasktool.set_process(100)
            need_restart = True
            await tasktool.exit(False)
        await execute("tasks", "create_task")(
            "安装插件", plug_file_path, install_task, user)
        return {
            "code": 0,
            "msg": ""
        }

    @app.route.post("/plugin/enable", level=2)
    async def enable_plugin(user: User, plug_name: str):  # 启用插件
        global need_restart
        os = OS(user)
        if (not await app.checker.check_func_permission(user, 2, "plugin")):
            raise HTTPException(status_code=403)
        plug_path = USER_PLUGIN_PATH+os.sep+plug_name
        if (not await os.path.exists(plug_path+".disable")):
            return {
                "code": 1,
                "msg": "找不到插件"
            }
        await os.rename(plug_path+".disable", plug_path)
        need_restart = True
        return {
            "code": 0,
            "msg": ""
        }

    @app.route.post("/plugin/disable", level=2)
    async def disable_plugin(user: User, plug_name: str):  # 禁用插件
        global need_restart
        os = OS(user)
        if (not await app.checker.check_func_permission(user, 2, "plugin")):
            raise HTTPException(status_code=403)
        plug_path = USER_PLUGIN_PATH+os.sep+plug_name
        need_restart = True
        if (not await os.path.exists(plug_path)):
            return {
                "code": 1,
                "msg": "找不到插件"
            }
        await os.rename(plug_path, plug_path+".disable")
        return {
            "code": 0,
            "msg": ""
        }
